/*
 *		jquery.ws.xmpp.js
 *
 *		Copyright 2012 Corey Wysong <cwysong85@gmail.com>
 *
 */
(function($) {
	$.xmpp = {
		/**
		 * Connect to server
		 *
		 */
		connect: function(options) {
			this.username = "testuser";
			this.password = "test123";
			this.resource = "jquery-websockets"; //(!resource ? "jquery-websockets" : resource);
			this._isConnected = false;
			this.protocol = window.location.protocol == "http:" ? "ws:" : "wss:";
			this._ws = new WebSocket(this.protocol + "//" + window.location.host + ":7070/ws/server?username=" + this.username + "&password=" + this.password + "&resource=" + this.resource, "xmpp");
			this._ws.onopen = this._onopen.bind(this);
			this._ws.onmessage = this._onmessage.bind(this);
			this._ws.onclose = this._onclose.bind(this);
			this.onMessage = options.onMessage;
			this.onPresence = options.onPresence;
			this.onIq = options.onIq;
		},
		disconnect: function() {
			if (!this.isConnected() || this._ws == null) {
				return;
			}
			this._ws.close();
		},
		isConnected: function() {
			return this._isConnected;
		},
		_disconnected: function() {
			// Send unavailable presence
			//this.setPresence("unavailable");
			clearInterval(this.interval);
			this._ws = null;
			this._isConnected = false;
			console.log("Disconnected");
		},
		_onopen: function() {
			var self = this;
			this._isConnected = true;
			console.log("Connected");
			this.setPresence();
			
			this.interval = setInterval(function() {self.sendPing()}, 10000 );
		},
		
		_onclose: function() {
			this._disconnected();
		},
		
		_onmessage: function(packet) {
		
			var response = $(this.fixBody("<data>" + packet.data + "</data>"));
			var self = this;
			$.each(response.find("message"), function(i, element) {
				try {
					var e = $(element);
					self.onMessage({
						from: e.attr("from"),
						body: e.find(".body").html(),
						attributes: e[0].attributes,
						toXML: packet.data,
						data: response.children()
					});
				} catch (error) {
					throw Error(error);
				}
			});
			
			$.each(response.find("iq"), function(i, element) {
				try {
					var e = $(element);
					if(e.find('ping').length == 1){
                        self.pingResponse(e);
                    }
                    else{
                        self.onIq(element);
                    }
				} catch(error){
					throw Error(error);
				}
			});
			
			$.each(response.find("presence"), function(i, element) {
				try {
					var e = $(element);
					self.onPresence({
						from: e.attr("from"),
						to: e.attr("to"),
						type: e.attr("type"),
						show: e.find("show").html(),
						toXML: packet.data
					});
				} catch(error){
					throw Error(error);
				}
			});
		},
		
		fixBody: function(html) {
			html = html.replace(/<\/body>/ig, "</div>")
			html = html.replace(/<body/ig, "<div class='body'")
			return html;
		},
		send: function(xml) {
			if (!this.isConnected() || this._ws == null) {
				throw Error("Not connected, cannot send packets.");
			}
			this._ws.send(xml);
			console.log("Sent: " + xml);
		},
		sendMessage: function(options, data) {
			var to = options.to;
			var body = options.body;
			if (options.resource != null) to += "/" + options.resource;
			else if (this.resource != "") to += "/" + this.resource;
			delete options;
			var message = "<message type='chat' to='" + to + "' xmlns='jabber:client'><body>" + body + "</body></message>";
			this.send(message);
		},
		
		setPresence: function(type) {
			var message;
			if (type == null) message = "<presence xmlns='jabber:client'></presence>";
			else if(type == "unavailable") message = "<presence xmlns='jabber:client' type='unavailable'></presence>";
			else message = "<presence xmlns='jabber:client'><show>" + type + "</show></presence>";
			this.send(message);
		},
		
		subscribeToPresence: function(to, subscribe){
			var message;
			if(to == null) return;
			if(subscribe) message = "<presence to='"+to+"' type='subscribed'/>";
			else message = "<presence to='"+to+"' type='unsubscribed'/>";
			this.send(message);
		},
		
		pingResponse: function(e){
			this.send("<iq from='"+e.attr('to')+"' to='"+e.attr('from')+"' id='"+e.attr('id')+"' type='result'/>");
		},
		
		sendPing: function(){
			this.send("<iq from='"+this.username+"@corey-wysongs-macbook-pro/"+this.resource+"' to='corey-wysongs-macbook-pro' id='c2s1' type='get'><ping xmlns='urn:xmpp:ping'/></iq>");
		},
		
		_textToXML: function(text) {
			console.log(text);
			var doc = null;
			if (window['DOMParser']) {
				var parser = new DOMParser();
				doc = parser.parseFromString(text, 'text/xml');
			} else if (window['ActiveXObject']) {
				var doc = new ActiveXObject("MSXML2.DOMDocument");
				doc.async = false;
				doc.loadXML(text);
			} else {
				throw Error('No DOMParser object found.');
			}
			return doc;
		},
		_serialize: function(elem) {
			var result;
			if (!elem) {
				return null;
			}
			if (typeof(elem.tree) === "function") {
				elem = elem.tree();
			}
			var nodeName = elem.nodeName;
			var i, child;
			if (elem.getAttribute("_realname")) {
				nodeName = elem.getAttribute("_realname");
			}
			result = "<" + nodeName;
			for (i = 0; i < elem.attributes.length; i++) {
				if (elem.attributes[i].nodeName != "_realname") {
					result += " " + elem.attributes[i].nodeName.toLowerCase() + "='" + elem.attributes[i].value.replace("&", "&amp;").replace("'", "&apos;").replace("<", "&lt;") + "'";
				}
			}
			if (elem.childNodes.length > 0) {
				result += ">";
				for (i = 0; i < elem.childNodes.length; i++) {
					child = elem.childNodes[i];
					if (child.nodeType == 1) {
						// normal element, so recurse
						result += this._serialize(child);
					} else if (child.nodeType == 3) {
						// text element
						result += child.nodeValue;
					}
				}
				result += "</" + nodeName + ">";
			} else {
				result += "/>";
			}
			return result;
		}
	}
})(jQuery);